#include <iostream>
#include <thread>
#include <map>

//#include <windows.h>
#include <WinSock2.h>

#pragma comment(lib, "ws2_32.lib")

#define BUFFER_SIZE 256

std::map<SOCKET, std::string> fdmap;

void print_last_error_info(DWORD error = ERROR_SUCCESS)
{
    if (error == ERROR_SUCCESS)
        error = GetLastError();

#ifdef UNICODE
    wchar_t buf[MAX_PATH];
    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                   NULL,
                   error,
                   0,
                   buf,
                   MAX_PATH,
                   NULL);
    wprintf(buf);
#else
    char buf[MAX_PATH];
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                   NULL,
                   error,
                   0,
                   buf,
                   MAX_PATH,
                   NULL);

    printf(buf);
#endif
}

void wsa_print_last_error_info(DWORD error = ERROR_SUCCESS)
{
    if (error == ERROR_SUCCESS)
        error = WSAGetLastError();

#ifdef UNICODE
    wchar_t buf[MAX_PATH];
    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                   NULL,
                   error,
                   0,
                   buf,
                   MAX_PATH,
                   NULL);
    wprintf(buf);
#else
    char buf[MAX_PATH];
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                   NULL,
                   error,
                   0,
                   buf,
                   MAX_PATH,
                   NULL);

    printf(buf);
#endif
}

void socket_basic_thread(SOCKET sock)
{
    char buf[BUFFER_SIZE];

    while (true)
    {
        auto len = recv(sock, buf, BUFFER_SIZE, 0);
        if (len > 0)
        {
            std::cout.write(buf, len);
            std::cout << std::endl;
            continue;
        }

        if (len == 0)
        {
            break;
        }

        auto err = WSAGetLastError();
        print_last_error_info(err);
        if (err = WSAECONNRESET)
            break;

        Sleep(100);
    }

    std::cout << fdmap[sock] << " disconnected" << std::endl;

    shutdown(sock, SD_BOTH);
    closesocket(sock);
}

void socket_basic()
{
    WSAData wd = {0};
    WSAStartup(MAKEWORD(2, 2), &wd);

    auto sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7834);
    addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    auto paddr = (sockaddr *)&addr;
    bind(sock, paddr, sizeof(addr));
    listen(sock, 5);

    int len;
    char peername[25];
    // getsockname(sock, paddr, &len);

    while (true)
    {
        auto nsock = accept(sock, paddr, &len);

        std::sprintf(peername, "%s:%d", inet_ntoa(addr.sin_addr), addr.sin_port);
        std::cout << peername << " connected" << std::endl;

        std::thread(socket_basic_thread, nsock).detach();
    }

    closesocket(sock);
    WSACleanup();
}

void socket_select()
{
    WSAData wd = {0};
    WSAStartup(MAKEWORD(2, 2), &wd);

    auto sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    char val = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(char));

    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7834);
    auto paddr = (sockaddr *)&addr;
    bind(sock, paddr, sizeof(addr));
    listen(sock, 5);

    fd_set set = {0};
    std::map<SOCKET, std::string> fds;
    int len = 0;
    char peername[25];
    getsockname(sock, paddr, &len);
    char buf[MAX_PATH];

    while (true)
    {
        FD_ZERO(&set);
        FD_SET(sock, &set);
        for (auto it = fds.begin(); it != fds.end(); it++)
        {
            FD_SET(it->first, &set);
        }
        if (select(0, &set, nullptr, nullptr, nullptr) < 0)
        {
            // std::cout << wsa_get_last_error_info() << std::endl;
            break;
        }

        for (auto it = fds.begin(); it != fds.end();)
        {
            auto fd = it->first;
            it++;

            if (!FD_ISSET(fd, &set))
            {
                continue;
            }

            len = recv(fd, buf, MAX_PATH, 0);
            if (len > 0)
            {
                std::cout.write(buf, len);
                std::cout << std::endl;
                continue;
            }

            std::cout << fds[fd] << " disconnected" << std::endl;

            if (len == 0)
            {
                fds.erase(fd);

                shutdown(fd, SD_BOTH);
                closesocket(fd);
                continue;
            }

            fds.erase(fd);
            closesocket(fd);
        }

        if (FD_ISSET(sock, &set))
        {
            auto nsock = accept(sock, paddr, &len);

            std::sprintf(peername, "%s:%d\0", inet_ntoa(addr.sin_addr), addr.sin_port);
            std::cout << peername << " connected" << std::endl;
            fds[nsock] = peername;
        }
    }

    std::cout << "exit soon" << std::endl;

    closesocket(sock);
    WSACleanup();
}

#pragma comment(lib, "user32.lib")

#define WM_SOCKET (WM_USER + 1)
WNDPROC old;

LRESULT socket_win_event_proc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
    auto sock = (SOCKET)wParam;
    sockaddr_in addr;
    int len;
    char buf[MAX_PATH];
    SOCKET nsock;

    switch (uMessage)
    {
    case WM_SOCKET:
        if (WSAGETASYNCERROR(lParam))
        {
            wsa_print_last_error_info();
            closesocket(sock);
            return -1;
        }

        switch (WSAGETSELECTEVENT(lParam))
        {
        case FD_READ:
            len = recv(sock, buf, MAX_PATH, 0);
            if (len > 0)
            {
                std::cout.write(buf, len);
                std::cout << std::endl;
            }
            else
            {
                shutdown(sock, SD_BOTH);
                closesocket(sock);
            }
            break;
        case FD_ACCEPT:
            nsock = accept(sock, (sockaddr *)&addr, &len);
            if (nsock == INVALID_SOCKET)
            {
                wsa_print_last_error_info();
                PostQuitMessage(-1);
                return -1;
            }

            WSAAsyncSelect(nsock, hWnd, WM_SOCKET, FD_READ | FD_CLOSE);
            break;
        case FD_CLOSE:
            closesocket(sock);
            break;
        }
        return -1;
    }

    return CallWindowProc(old, hWnd, uMessage, wParam, lParam);
}

void socket_win_event()
{
    auto hwnd = CreateWindow(L"BUTTON", L"test", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr);
    old = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)socket_win_event_proc);

    WSAData data;
    WSAStartup(MAKEWORD(2, 2), &data);

    auto sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7834);
    auto paddr = (sockaddr *)&addr;
    bind(sock, paddr, sizeof(addr));
    listen(sock, 5);

    if (WSAAsyncSelect(sock, hwnd, WM_SOCKET, FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR)
    {
        wsa_print_last_error_info();
        return;
    }

    MSG msg;
    BOOL ret;

    while ((ret = GetMessage(&msg, hwnd, 0, 0)) != 0)
    {
        if (ret == -1)
            break;

        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    WSACleanup();
}

#include <map>
#include <vector>

void socket_event()
{
    WSAData data;
    WSAStartup(MAKEWORD(2, 2), &data);

    auto sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    char reuse = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, 1);

    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7834);
    auto paddr = (sockaddr *)&addr;
    bind(sock, paddr, sizeof(addr));
    listen(sock, 5);

    auto ev = WSACreateEvent();
    WSAEventSelect(sock, ev, FD_ACCEPT | FD_CLOSE);

    std::map<SOCKET, HANDLE> fdmap;
    fdmap[sock] = ev;

    HANDLE evs[MAX_PATH];
    int index = 0;
    WSANETWORKEVENTS events;
    int len;
    char buf[MAX_PATH];

    while (true)
    {
        index = 0;
        for (auto it = fdmap.begin(); it != fdmap.end(); it++)
        {
            evs[index] = it->second;
            ++index;
        }
        WSAWaitForMultipleEvents(index, evs, FALSE, WSA_INFINITE, FALSE);

        for (auto it = fdmap.begin(); it != fdmap.end();)
        {
            auto fd = it->first;

            WSAEnumNetworkEvents(fd, fdmap[fd], &events);
            // WSAResetEvent(fdmap[fd]);

            if (events.lNetworkEvents & FD_ACCEPT)
            {
                auto nsock = accept(fd, paddr, &len);

                ev = WSACreateEvent();
                WSAEventSelect(nsock, ev, FD_READ | FD_CLOSE);

                fdmap[nsock] = ev;

                std::cout << "connected" << std::endl;

                it++;
            }
            else if (events.lNetworkEvents & FD_READ)
            {
                len = recv(fd, buf, MAX_PATH, 0);
                if (len > 0)
                {
                    std::cout.write(buf, len);
                    std::cout << std::endl;

                    it++;
                    continue;
                }

                WSACloseEvent(fdmap[fd]);

                if (len == 0)
                {
                    shutdown(fd, SD_BOTH);
                }

                closesocket(fd);

                it = fdmap.erase(it);

                std::cout << "disconnected" << std::endl;
            }
            else if (events.lNetworkEvents & FD_CLOSE)
            {
                WSACloseEvent(fdmap[fd]);
                closesocket(fd);

                it = fdmap.erase(it);

                std::cout << "disconnected2" << std::endl;
            }
        }
    }

    WSACleanup();
}

struct session_info
{
    WSAOVERLAPPED overlapped;
    char buffer[MAX_PATH];
    sockaddr_in raddr;
    sockaddr_in laddr;
    WSABUF buf;
    SOCKET sock;
    DWORD len;
    DWORD flags;
    int operation;
};

void socket_overlapped_event()
{
    WSAData data;
    WSAStartup(MAKEWORD(2, 2), &data);

    auto sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED);

    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7834);
    auto paddr = (sockaddr *)&addr;
    bind(sock, paddr, sizeof(addr));
    listen(sock, 5);

    int len;

    while (true)
    {
        auto nsock = accept(sock, paddr, &len);
        if (nsock < 0)
            break;

        auto info = new session_info;
        info->sock = nsock;
        info->buf.buf = info->buffer;
        info->buf.len = MAX_PATH;
        info->overlapped.hEvent = WSACreateEvent();

        auto ret = WSARecv(nsock, &info->buf, 1, &info->len, &info->flags, &info->overlapped, nullptr);
        if (ret == SOCKET_ERROR)
        {
            std::cout << ret << std::endl;
            if (WSAGetLastError() != WSA_IO_PENDING)
            {
                print_last_error_info();

                closesocket(nsock);
                WSACloseEvent(info->overlapped.hEvent);
                delete info;
            }
        }

        // WSAWaitForMultipleEvents();
        // WSAGetOverlappedResult();
    }

    WSACleanup();
}

void socket_overlapped_handler(IN DWORD dwError, IN DWORD cbTransferred, IN LPWSAOVERLAPPED lpOverlapped, IN DWORD dwFlags)
{
    std::cout << 11 << std::endl;
    auto info = (session_info *)lpOverlapped->Pointer;

    if (dwError == ERROR_SUCCESS)
    {
        if (cbTransferred > 0)
        {
            std::cout.write(info->buf.buf, cbTransferred);
            std::cout << std::endl;

            WSARecv(info->sock, &info->buf, 1, &info->len, &info->flags, lpOverlapped, socket_overlapped_handler);
            return;
        }

        if (cbTransferred == 0)
            shutdown(info->sock, SD_BOTH);
    }

    closesocket(info->sock);
    WSACloseEvent(lpOverlapped->hEvent);
    delete info;
}

void socket_overlapped_routine()
{
    WSAData data;
    WSAStartup(MAKEWORD(2, 2), &data);

    auto sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, WSA_FLAG_OVERLAPPED);

    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7834);
    auto paddr = (sockaddr *)&addr;
    bind(sock, paddr, sizeof(addr));
    listen(sock, 5);

    int len;

    while (true)
    {
        auto nsock = accept(sock, paddr, &len);
        if (nsock < 0)
            break;

        auto info = new session_info;
        info->sock = nsock;
        info->buf.buf = info->buffer;
        info->buf.len = MAX_PATH;
        info->overlapped.hEvent = WSACreateEvent();

        auto ret = WSARecv(nsock, &info->buf, 1, &info->len, &info->flags, &info->overlapped, socket_overlapped_handler);
        if (ret == SOCKET_ERROR)
        {
            if (WSAGetLastError() != WSA_IO_PENDING)
            {
                print_last_error_info();

                closesocket(nsock);
                WSACloseEvent(info->overlapped.hEvent);
                delete info;
            }
        }
    }

    WSACleanup();
}

void socket_overlapped()
{
    // socket_overlapped_event();
    // socket_overlapped_routine();
}

DWORD WINAPI socket_iocp_handler(LPVOID args)
{
    auto iocp = (HANDLE)args;
    DWORD len;
    session_info *psession;
    LPOVERLAPPED ov;

    while (true)
    {
        GetQueuedCompletionStatus(iocp, &len, (PULONG_PTR)&psession, &ov, WSA_INFINITE);

        if (psession == nullptr)
            break;

        if (psession->operation == 0)
        {
            if (len > 0)
            {
                std::cout.write(psession->buf.buf, len);
                std::cout << std::endl;

                if (WSARecv(psession->sock, &psession->buf, 1, &psession->len, &psession->flags, ov, nullptr) == SOCKET_ERROR)
                {
                    auto err = WSAGetLastError();
                    if (err != WSA_IO_PENDING)
                    {
                        wsa_print_last_error_info(err);

                        closesocket(psession->sock);

                        delete psession;
                    }
                }
            }
            else if (len == 0)
            {
                shutdown(psession->sock, SD_BOTH);
                closesocket(psession->sock);

                delete psession;
            }
            else
            {
            }
        }
        else
        {
        }
    }

    return 0;
}

void socket_iocp()
{
    WSAData data;
    WSAStartup(MAKEWORD(2, 2), &data);

    auto sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7834);
    auto paddr = (sockaddr *)&addr;
    bind(sock, paddr, sizeof(addr));
    listen(sock, 5);

    auto iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 2);
    if (iocp == nullptr)
        return;

    CreateThread(nullptr, 0, socket_iocp_handler, iocp, 0, nullptr);

    int len;

    while (true)
    {
        auto nsock = accept(sock, paddr, &len);

        auto info = new session_info;
        info->sock = nsock;
        info->buf.buf = info->buffer;
        info->buf.len = MAX_PATH;
        info->operation = 0;

        CreateIoCompletionPort((HANDLE)nsock, iocp, (ULONG_PTR)info, 0);

        if (WSARecv(nsock, &info->buf, 1, &info->len, &info->flags, &info->overlapped, nullptr) == SOCKET_ERROR)
        {
            auto err = WSAGetLastError();
            if (err != WSA_IO_PENDING)
            {
                wsa_print_last_error_info(err);

                closesocket(info->sock);
                delete info;
            }
        }
    }

    WSACleanup();
}

void socket_iocpr()
{
    WSAData data;
    WSAStartup(MAKEWORD(2, 2), &data);

    auto sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7834);
    auto paddr = (sockaddr *)&addr;
    bind(sock, paddr, sizeof(addr));
    listen(sock, 5);

    int len;

    while (true)
    {
        auto nsock = accept(sock, paddr, &len);

        BindIoCompletionCallback((HANDLE)nsock, [](DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
                                 {
            auto session = (session_info *)lpOverlapped;

            if (dwNumberOfBytesTransfered > 0)
            {
                std::cout.write(session->buffer, dwNumberOfBytesTransfered);
                std::cout << std::endl;

                WSARecv(session->sock, &session->buf, 1, &session->len, &session->flags, &session->overlapped, nullptr);
                return;
            }

            if (dwNumberOfBytesTransfered == 0)
            {
                shutdown(session->sock, SD_BOTH);
            }

            closesocket(session->sock);
            delete session; },
                                 0);

        auto session = new session_info;
        session->sock = nsock;
        session->flags = 0;
        session->buf.buf = session->buffer;
        session->buf.len = MAX_PATH;

        WSARecv(nsock, &session->buf, 1, &session->len, &session->flags, &session->overlapped, nullptr);
    }

    WSACleanup();
}

#include <MSWSock.h>
#include <list>

LPFN_ACCEPTEX lpfnAcceptEx = nullptr;
GUID GuidAcceptEx = WSAID_ACCEPTEX;
LPFN_DISCONNECTEX lpfnDisconnectEx = nullptr;
GUID guidDisconnectEx = WSAID_DISCONNECTEX;
LPFN_GETACCEPTEXSOCKADDRS lpfnGetAcceptExSockaddrs = nullptr;
GUID guidgetAcceptSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
std::list<SOCKET> fds;
CRITICAL_SECTION fdlock;
std::list<session_info *> sess;
CRITICAL_SECTION seslock;

enum socket_operation
{
    socket_read = 0,
    socket_write,
    socket_accept,
    socket_disconnect,
    socket_connect
};

SOCKET get_socket()
{
    SOCKET sock = INVALID_SOCKET;
    EnterCriticalSection(&fdlock);
    if (fds.empty())
    {
        sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    }
    else
    {
        sock = fds.front();
        fds.pop_front();
    }
    LeaveCriticalSection(&fdlock);

    return sock;
}

void socket_iocp_reuse()
{
    WSAData data;
    if (WSAStartup(MAKEWORD(2, 2), &data) != NO_ERROR)
    {
        return;
    }

    InitializeCriticalSection(&fdlock);

    auto sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    DWORD dwBytes;
    WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &dwBytes, NULL, NULL);
    WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidDisconnectEx, sizeof(guidDisconnectEx), &lpfnDisconnectEx, sizeof(lpfnDisconnectEx), &dwBytes, NULL, NULL);
    WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidgetAcceptSockaddrs, sizeof(guidgetAcceptSockaddrs), &lpfnGetAcceptExSockaddrs, sizeof(lpfnGetAcceptExSockaddrs), &dwBytes, NULL, NULL);

    sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(7834);
    auto paddr = (sockaddr *)&addr;
    bind(sock, paddr, sizeof(addr));
    listen(sock, 5);

    auto session = new session_info;
    session->sock = get_socket();
    session->buf.buf = session->buffer;
    session->operation = socket_accept;

    auto iocp = CreateIoCompletionPort((HANDLE)sock, nullptr, (ULONG_PTR)session, 2);

    lpfnAcceptEx(sock, session->sock, session->buffer, 0, sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &session->len, &session->overlapped);

    DWORD trans;
    ULONG_PTR key;
    session_info *nsession;
    while (true)
    {
        auto ret = GetQueuedCompletionStatus(iocp, &trans, &key, (LPOVERLAPPED *)&session, WSA_INFINITE);
        if (!ret)
        {
            if (session == nullptr)
                break;
        }

        switch (session->operation)
        {
        case socket_read:
            break;
        case socket_write:
            break;
        case socket_accept:
            setsockopt(session->sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (const char *)&sock, sizeof(sock));

            nsession = new session_info;
            nsession->sock = session->sock;
            nsession->buf.buf = nsession->buffer;
            nsession->operation = socket_read;
            CreateIoCompletionPort((HANDLE)nsession->sock, iocp, (ULONG_PTR)nsession, 0);

            WSARecv(nsession->sock, &nsession->buf, MAX_PATH, &nsession->len, &nsession->flags, &nsession->overlapped, nullptr);
            break;
        case socket_disconnect:
            break;
        default:
            break;
        }
    }

    closesocket(sock);
    CloseHandle(iocp);
    DeleteCriticalSection(&fdlock);
    WSACleanup();
}

void socket_udp()
{
}

void socket_raw()
{
}

void serial()
{
}

void file_dir()
{
}

void mem()
{
}

void process()
{
}

void ipc()
{
}

void conc()
{
}

void window()
{
}

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

char strr[10]; //这里面存的是自动生成的6位口令

// static int Count = 0;//这是要统计破解的次数

void respond_password_generated()
{
    srand((unsigned)time(0));
    int n[6] = {0};
    int i;
    for (i = 0; i < 6; i++)
    {
        n[i] = rand() % 10;
        strr[i] = n[i] + '0';
    }
}
int respond_violence(int c)
{
    c = 0;
    char b[7];
    int i, j;
    for (i = 0; i <= 999999; i++)
    {
        int k = i;
        for (j = 5; j >= 0; j--)
        {
            b[j] = k % 10 + '0';
            k /= 10;
        }
        if (!strcmp(strr, b))
        {
            break;
        }
        c++;
    }
    return c;
}

#define num 2

/*
Windows程序是事件驱动的，对于一个窗口，它的大部分例行维护是由系统维护的。
每个窗口都有一个消息处理函数。
在消息处理函数中，对传入的消息进行处理。系统内还有它自己的缺省消息处理函数。
客户写一个消息处理函数，在窗口建立前，将消息处理函数与窗口关联。这样，每当有消息产生时，
就会去调用这个消息处理函数。通常情况下，客户都不会处理全部的消息，而是只处理自己感兴趣的消息，
其他的，则送回到系统的缺省消息处理函数中去。
系统会将针对这个程序的消息依次放到程序的“消息队列”中，由程序自己依次取出消息，
在分发到对应的窗口中去。因此，建立窗口后，将进入一个循环。在循环中，取出消息、派发消息，
循环往复，直到取得的消息是退出消息。循环退出后，程序即结束。
*/
//消息处理函数 。参数:窗口句柄，消息，消息参数，消息参数
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

/*
hinstance - 该参数为Windows 为应用程序生成的实例句柄。实例是用来跟踪资源的指针。
hprevinstance 当前已不再使用该参数，之前用来跟踪应用程序的前一个实例，即程序的父亲的程序实例。
ipcmdline - 一个以NULL结尾的字符串，类似于标准main(int argc,char** argv)中的命令行参数，
但没有单独的argc来指示命令行参数数量。
ncmdshow—— 最后一个参数是启动期间传递给应用程序的一个整数，指出如何打开程序的窗口。
事实上，基本没用，但ncmdshow的值一般会用于ShowWindows()中使用，用来设置新建子窗口的形式。
*/

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("MyWindows"); //窗口类名称

    //定制"窗口类"结构
    WNDCLASS wndclass;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc; //关联消息处理函数
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);     //图标
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);       //光标
    wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); //画刷
    //将客户区的背景颜色改成和按钮一样  +1是为了防止出现NULL
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;

    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("这个程序需要在 Windows NT 才能执行！"), szAppName, MB_ICONERROR);
        return 0;
    }
    //建立窗口
    auto hwnd = CreateWindow(szAppName,                               //窗口类名称
                             TEXT("PasswordBreak"),                   //窗口标题
                             WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, //窗口风格

                             /*三个参数的含义：
                产生一个层叠的窗口，一个层叠的窗口有一个标题条和一个边框，与 WS_TILED 风格相同
                创建一个有标题框的窗口（包含了 WS_BODER 风格）
                创建一个在标题条上带有窗口菜单的窗口，必须同时设定 WS_CAPTION 风格
                */

                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             CW_USEDEFAULT,
                             NULL,
                             NULL,
                             hInstance,
                             NULL);

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);

    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg); //转换消息
        DispatchMessage(&msg);  //派发消息
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;
    TCHAR *str[num] = {TEXT("自动生成六位口令"), TEXT("暴力破解六位口令"), TEXT("音乐")};
    static int cxchar, cychar;
    static HWND hwndButton[num];
    //存放子窗口的句柄
    int i, id, co;

    static int winner = -1, flag = 0, Count = 0; //标记哪个选项被选中

    switch (message)
    {
    case WM_CREATE:
        cxchar = LOWORD(GetDialogBaseUnits());
        cychar = HIWORD(GetDialogBaseUnits());
        /*
        获取字体的横/纵坐标：返回值是一个8位16进制数，高4位存放字体的高度，低4位存放字体的宽度，
        可以通过以下语句了获取字体的高和宽
        GetDialogBaseUnits函数返回的水平基本单位同系统字体中字符以像素为单位的平均宽度相等；
        垂直基本单位同系统字体中字符的以像素为单位的平均高度相等；
        对于一个没有使用系统字体的对话框基本单位相等于对话框字体字符以像素为单位的平均宽度和平均高度。
        */
        GetWindowRect(hwnd, &rect);
        MoveWindow(hwnd, rect.left, rect.top, 40 * cxchar, 20 * cychar, TRUE);
        /*
hWnd是窗口的句柄。
X是窗口在X轴的位置。
Y是窗口在Y辆的位置。
nWidth是窗口的宽度。
nHeight是窗口的高度。
bRepaint是设置是否重画窗口和父窗口。
当设置为TRUE时，就进行重画。当设置为FALSE时，
就不进行重画，需要手功进行更新指定的区域。
        */
        for (i = 0; i < num; i++)
        {
            hwndButton[i] = CreateWindow(TEXT("button"), str[i],
                                         BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE,
                                         8 * cxchar, cychar * (2 + 3 * i), 20 * cxchar, 7 * cychar / 4,
                                         hwnd, (HMENU)i, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
        }

        CreateWindow(TEXT("button"), TEXT("选项"),
                     BS_GROUPBOX | WS_CHILD | WS_VISIBLE,
                     3 * cxchar, cychar / 10, 30 * cxchar, 37 * cychar / 4,
                     hwnd, (HMENU)(num + 1), ((LPCREATESTRUCT)lParam)->hInstance, NULL);

        CreateWindow(TEXT("button"), TEXT("提交"),
                     BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
                     5 * cxchar, 13 * cychar,
                     //按钮的上下位置
                     9 * cxchar, 9 * cychar / 4,
                     //按钮的长和宽
                     hwnd, (HMENU)(num + 2), ((LPCREATESTRUCT)lParam)->hInstance, NULL);
        CreateWindow(TEXT("button"), TEXT("破解次数"),
                     BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
                     20 * cxchar, 13 * cychar,
                     //按钮的左右和上下位置
                     9 * cxchar, 9 * cychar / 4,
                     //按钮的长和宽
                     hwnd, (HMENU)(num + 3), ((LPCREATESTRUCT)lParam)->hInstance, NULL);
        return 0;
    case WM_COMMAND:
        id = LOWORD(wParam); //获取子窗口控件的id
        if (id < num)
        {
            winner = id; //选中哪个选项
        }
        switch (id)
        {
        case num + 2: //如果点了提交的按钮
            if (winner == -1)
            {
                MessageBox(hwnd, TEXT("没有选中任何选项！"), TEXT("提示"), MB_OK);
            }
            else if (winner == 0) //如果点了自动生成6位口令
            {
                flag = 1;
                respond_password_generated();
                CHAR szdemo[20] = "\0";
                sprintf(szdemo, TEXT("%s %s"), TEXT("生成的口令是："), strr);
                MessageBox(hwnd, TEXT(szdemo), TEXT("提示"), MB_OK);
            }
            else if (winner == 1)
            {
                if (flag)
                {
                    respond_violence();
                    MessageBox(hwnd, TEXT("口令已破解"), TEXT("提示："), MB_OK);
                }
                else
                {
                    MessageBox(hwnd, TEXT("未生成口令！"), TEXT("提示："), MB_OK);
                }
            }
            break;
        case num + 3: //如果点了显示破解次数的按钮
        {
            co = respond_violence(Count);
            // printf("%d\n", co);
            // printf("%s\n", strr);
            CHAR szdemo1[40] = "\0";
            sprintf(szdemo1, TEXT("%s %d"), TEXT("尝试的次数为："), co);
            MessageBox(hwnd, TEXT(szdemo1), TEXT("提示"), MB_OK);
            break;
        }
        }
        return 0;

        //        case WM_PAINT:
        //                hdc = BeginPaint(hwnd, &ps);
        //                GetClientRect(hwnd, &rect);
        //
        //                EndPaint(hwnd, &ps);
        //                return 0;

        //        case WM_LBUTTONDOWN:
        MessageBox(hwnd, TEXT("哎呀~我被按了一下~"), TEXT("好舒服~"), MB_OK);
        //            return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        //当用户关闭窗口，窗口销毁，程序需结束，发退出消息，以退出消息循环
        return 0;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

int main()
{
    // socket_basic();
    // socket_select();
    // socket_win_event();
    // socket_event();
    // socket_overlapped();
    // socket_iocp();
    // socket_iocpr();
    // socket_iocp_reuse();
    socket_udp();
    socket_raw();
    serial();

    file_dir();
    mem();
    process();
    ipc();
    conc();

    window();

    return 0;
}
